﻿using Microsoft.AspNetCore.Routing;

namespace Abc.Base;

/// <summary>
/// Web 全局调用日志记录
/// </summary>
public class LogFilterAttribute : IAsyncActionFilter
{
    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        #region 拦截之前

        var logcontent = $"ID:{context.ActionDescriptor.Id}";
        logcontent += context.HttpContext.GetWebVisitInfo();

        //提交的参数
        logcontent += $"参数 ActionArguments:{context.ActionArguments.ToJson()}";

        if (context.ModelState != null && context.ModelState.IsValid == false)
        {
            //验证信息
            var verifications = context.ModelState.ToDictionary(x => x.Key, v => v.Value.Errors.Select(o => o.ErrorMessage).ToList());

            logcontent += $"数据验证失败返回：{verifications.ToJson()}";
        }
        var logFloderName = GetLogFloderName(context.HttpContext, context.RouteData);
        // AppEx.GetLogger(logFloderName: logFloderName, retainedFileCountLimit: 24).Debug(logcontent);

        #endregion 拦截之前

        //执行
        var resultContext = await next();

        #region 拦截之后

        //访问返回
        if (resultContext.Result is JsonResult)
        {
            if (resultContext.Result is JsonResult jsonresult) logcontent += $"访问返回：{jsonresult.Value.ToJson()}";
        }

        #endregion 拦截之后

        var _logger = AppEx.GetLogger(logFloderName: "LogFilterAttribute", retainedFileCountLimit: 20);
        // 异常拦截
        if (resultContext.Exception != null)
        {
            //操作或操作筛选器导致异常
            // Exception thrown by action or action filter.
            // 设置为null以处理异常。
            //context.Exception = null;

            logcontent += $"\r\n异常：{resultContext.Exception.ToStringEx()}";
            _logger?.Error(logcontent);
        }
        _logger?.Debug(logcontent);
    }

    /// <summary>
    /// 获取文件夹名称
    /// </summary>
    /// <param name="httpcontext"></param>
    /// <param name="routeData"></param>
    /// <returns></returns>
    private static string GetLogFloderName(HttpContext httpcontext, RouteData routeData)
    {
        var logFloderName = "default";

        var area = routeData.Values["area"]?.ToString() ?? "";
        var controller = routeData.Values["controller"]?.ToString() ?? "";
        var action = routeData.Values["action"]?.ToString() ?? "";

        if (!string.IsNullOrWhiteSpace(area))
        {
            logFloderName = area;
        }
        else
        {
            var path1 = $"/{area}/{controller}/{action}".Trim('/');//  /test/test
            var path = httpcontext.Request.Path.ToString(); //path:api/test/test
            if (path.Contains(path1))
            {
                area = path.RemoveLastStr(path1);
                if (!string.IsNullOrWhiteSpace(area))
                {
                    logFloderName = area.Trim("//").Trim('/');
                }
            }
        }
        if (!string.IsNullOrWhiteSpace(controller))
        {
            logFloderName += $"\\{controller}";
        }
        logFloderName = logFloderName.Trim('\\');

        return logFloderName;
    }
}